//  Copyright (c) Microsoft Corporation.  All Rights Reserved.

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IdentityModel.Selectors;

namespace EAI.SAML
{
    public class EAISamlSubjectConfirmation
    {
        Uri method;
        // The below property has not been implemented yet.
        // <BaseID>, <NameID>, or <EncryptedID> [Optional]
        // Identifies the entity expected to satisfy the enclosing subject confirmation requirements.
        EAISamlSubjectConfirmationData subjectConfirmationData;

        bool isReadOnly = false;

        public EAISamlSubjectConfirmation(Uri method)
            : this(method, null)
        {
        }

        public EAISamlSubjectConfirmation(Uri method, EAISamlSubjectConfirmationData subjectConfirmationData)
        {
            if (method == null)
                throw new ArgumentNullException("method");

            this.method = method;
            this.subjectConfirmationData = subjectConfirmationData;
        }

        public EAISamlSubjectConfirmation(XmlReader reader, EAISamlSerializer serializer, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)
        {
            this.ReadXml(reader, serializer, keyInfoSerializer, outOfBandTokenResolver);
        }

        public Uri Method
        {
            get { return this.method; }
            set
            {
                if (value == null)
                    throw new ArgumentNullException("value");

                if (this.isReadOnly)
                    throw new InvalidOperationException("The Object is ReadOnly.");

                this.method = value;
            }
        }

        public EAISamlSubjectConfirmationData SubjectConfirmationData
        {
            get { return this.subjectConfirmationData; }
            set
            {
                if (this.isReadOnly)
                    throw new InvalidOperationException("The Object is ReadOnly.");

                this.subjectConfirmationData = value;
            }
        }

        void CheckObjectValidity()
        {
            if (this.method == null)
                throw new InvalidOperationException("saml:SubjectConfirmation should specify a method.");
        }

        public void MakeReadOnly()
        {
            if (!this.isReadOnly)
            {
                if (this.subjectConfirmationData != null)
                    this.subjectConfirmationData.MakeReadOnly();
                this.isReadOnly = true;
            }
        }

        public virtual void ReadXml(XmlReader reader, EAISamlSerializer serializer, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");

            if (serializer == null)
                throw new ArgumentNullException("serializer");

            string attributeValue = reader.GetAttribute(EAISamlConstants.MethodAttribute);
            if (String.IsNullOrEmpty(attributeValue))
                throw new SecurityTokenException("<saml:SubjectConfirmation> element is missing the required 'Method' attribute.");

            this.method = new Uri(attributeValue);

            reader.Read();
            if (reader.IsStartElement(EAISamlConstants.SubjectConfirmationData, EAISamlConstants.Namespace))
                this.subjectConfirmationData = serializer.LoadSubjectConfirmationData(reader, keyInfoSerializer, outOfBandTokenResolver);

            reader.ReadEndElement();
        }

        public virtual void WriteXml(XmlWriter writer, SecurityTokenSerializer tokenSerializer)
        {
            CheckObjectValidity();

            if (writer == null)
                throw new ArgumentNullException("writer");

            writer.WriteStartElement(EAISamlConstants.SubjectConfirmation, EAISamlConstants.Namespace);
            writer.WriteAttributeString(EAISamlConstants.MethodAttribute, this.method.ToString());
            if (this.subjectConfirmationData != null)
                this.subjectConfirmationData.WriteXml(writer, tokenSerializer);

            writer.WriteEndElement();
        }
    }
}
